package com.imooc.imoocbilibili.interceptor;

import cn.hutool.core.util.StrUtil;
import com.imooc.imoocbilibili.annotation.NoAuth;
import com.imooc.imoocbilibili.entity.User;
import com.imooc.imoocbilibili.enums.ErrorResultEnum;
import com.imooc.imoocbilibili.exception.RRException;
import com.imooc.imoocbilibili.service.UserService;
import com.imooc.imoocbilibili.utils.TokenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Optional;

/**
 * 需要注册使用 {@link InterceptorConfiguration}
 */
public class LoginInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private UserService userService;

    public LoginInterceptor() {
        super();
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // NoAuth注解的方法无须登录,直接放行,也可以注册拦截器时排除要放行的地址
        Optional<NoAuth> scopeLevel = this.getScopeLevel(handler);
        if (scopeLevel.isPresent()) {
            return true;
        }

        String token = request.getHeader("token") != null ? request.getHeader("token") : request.getParameter("token");
        if (StrUtil.isBlank(token)) {
            throw new RRException(ErrorResultEnum.NEED_LOGIN);
        }

        Long userId = TokenUtil.verifyToken(token);
        this.setToThreadLocal(userId);
        return true;
    }

    private void setToThreadLocal(Long userId) {
        User user = userService.getById(userId);
        ThreadUser.set(user);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        ThreadUser.clear();
        super.afterCompletion(request, response, handler, ex);
    }

    /**
     * 获取方法上的注解
     */
    private Optional<NoAuth> getScopeLevel(Object handler) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            NoAuth scopeLevel = handlerMethod.getMethod().getAnnotation(NoAuth.class);
            if (scopeLevel == null) {
                return Optional.empty();
            }
            return Optional.of(scopeLevel);
        }
        return Optional.empty();
    }

}
